#include<iostream>
#include<typeinfo>
#include<string>
#include<any>
using namespace std;

class Any
{
 private:   
   class holder
   {
     public:
       virtual ~holder(){}
       virtual const std::type_info& type()=0; //获取子类对象保存的数据类型
       //针对当前对象自身克隆出一个新子类对象,方便我们后续针对一个Any对象构造新的Any对象
       virtual holder* clone() = 0; 
   };

   template<class T>
   class placeholder : public holder
   {
     public:
       ~placeholder()
       {}
       placeholder(const T& val):_val(val){}
       virtual const std::type_info& type(){return typeid(_val);}
       virtual holder* clone() {return new placeholder<T>(_val);}
     public:
        T _val;  
   };

   holder* _content;
public:

   //交换子类对象
    Any& swap(Any& otehr)
    {
        std::swap(_content,otehr._content);
        return *this;
    }                                                                                                                                                     

    Any():_content(nullptr){};

    template<class T>
    Any(const T&val)
    :_content(new placeholder<T>(val))
    {}

    Any(const Any& other)
    :_content(other._content ? other._content->clone() : nullptr) //判断是否为空 不为空则clone
    {}

    ~Any()
    {delete _content;}
    
    template<class T>
    T* get() //返回子类对象保存的数据的指针
    {
        return &((placeholder<T>*)_content)->_val;
    }

    //为val构造一个临时的通用容器,然后与当前容器自身进行指针交换,临时对象释放的时候,原先保存的数据也就被释放
    template<class T>
    Any& operator=(const T& val)//返回值Any&是为了能连续赋值
    {
        Any(val).swap(*this);
        return *this;
    }
    Any& operator=(const Any& other)
    {
        // 通过外部other对象构造一个临时Any对象
         Any(other).swap(*this);
        return *this;
    }
    
};

class Test
{
public:
   Test(){cout << "构造" << endl;}
   ~Test(){cout << "析构" << endl;}
   Test(const Test& t){cout << "拷贝"<< endl;}
};


int main()
{
  std::any a;//any a(10)
  a = 10;
  cout << "a: " << std::any_cast<int>(a) << endl;
  cout << "*a: " << *std::any_cast<int>(&a) << endl;  

  a  = string("hello C++17");
  cout << "string: " << std::any_cast<string>(a) << endl;
  cout << "*string: " << *std::any_cast<string>(&a) << endl;
  return 0;
}

// int main()
// {

//    Any a1 = 10;
//    Any a2;
//    Any a3;
//    a3 = a2 = a1;
//    cout << "a2: " << *a2.get<int>() << endl;
//    cout << "a3: " << *a3.get<int>() << endl;
//     return 0;
// }

//     Any a;
//     a = 10;
//     int* pa = a.get<int>();
//     cout << "a:"<<*pa<<endl;
//     a = string("Any");
//     cout << *a.get<std::string>();